namespace Guia.Elements
{
    using System;
    using System.Diagnostics.Contracts;
    using System.Windows.Automation;
    using Guia.Core;
    using Guia.Locator;

    /// <summary>
    /// This class represents a TabControl.
    /// </summary>
    public class TabControl : UiElement
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="TabControl"/> class.
        /// </summary>
        /// <param name="automationElement">
        /// The automation element.
        /// </param>
        public TabControl(AutomationElement automationElement) : base(automationElement)
        {
        }

        /// <summary>
        /// Gets the default-condition to find a control by its type.
        /// </summary>
        public static SearchCondition ControlTypeCondition
        {
            get { return SearchCondition.ByControlType(ControlType.Tab); }
        }

        /// <summary>
        /// Gets the selected Tab. If no TabItem was selected, null is returned.
        /// </summary>
        public TabItem SelectedTab
        {
            get
            {
                SelectionPattern selectionPattern = this.GetSelectionPattern();
                AutomationElement[] automationElements = selectionPattern.Current.GetSelection();
                if (automationElements.Length == 1)
                {
                    return new TabItem(automationElements[0]);
                }
                else
                {
                    return null;
                }
            }
        }

        /// <summary>
        /// Gets all TabItems of this TabControl.
        /// </summary>
        /// <returns>
        /// All TabItems.
        /// </returns>
        public TabItem[] AllTabs
        {
            get { return this.GetAll<TabItem>(); }
        }

        /// <summary>
        /// Gets the TabItem with the given name (Header).
        /// </summary>
        /// <param name="tabName">
        /// The TabItem with the name (Header) given.
        /// </param>
        /// <exception cref="ArgumentNullException">This exception is thrown if tabName is null.</exception>
        public TabItem this[string tabName]
        {
            get
            {
                return this.GetTab(tabName);
            }
        }

        /// <summary>
        /// Gets the TabItem at the given position.
        /// </summary>
        /// <param name="index">The index of the desired TabItem.</param>
        /// <returns>The TabItem at the given position.</returns>
        /// <exception cref="ElementNotFoundException">This exception is thrown if no TabItem exist at the given position.</exception>
        /// <exception cref="ArgumentOutOfRangeException">This exception is thrown if the index is out of range.</exception>
        public TabItem this[int index]
        {
            get
            {
                return this.GetTab(index);
            }
        }

        /// <summary>
        /// Gets the TabItem with the given name (Header).
        /// </summary>
        /// <param name="tabName">
        /// The name (header value) of the TabItem.
        /// </param>
        /// <returns>
        /// The TabItem with the name (Header) given.
        /// </returns>
        /// <exception cref="ArgumentNullException">This exception is thrown if tabName is null.</exception>
        public TabItem GetTab(string tabName)
        {
            Contract.Requires<ArgumentNullException>(tabName != null);
            return this.GetByName<TabItem>(tabName);
        }

        /// <summary>
        /// Gets the TabItem at the given position.
        /// </summary>
        /// <param name="index">The index of the desired TabItem.</param>
        /// <returns>The TabItem at the given position.</returns>
        /// <exception cref="ElementNotFoundException">This exception is thrown if no TabItem exist at the given position.</exception>
        /// <exception cref="ArgumentOutOfRangeException">This exception is thrown if the index is out of range.</exception>
        public TabItem GetTab(int index)
        {
            Contract.Requires<ArgumentOutOfRangeException>(index >= 0 && index < this.AllTabs.Length);
            try
            {
                TabItem[] items = this.AllTabs;
                TabItem item = items[index];

                return item;
            }
            catch (IndexOutOfRangeException)
            {
                throw new ElementNotFoundException("No TabItem found with the index " + index);
            }
        }

        /// <summary>
        /// Returns the SelectionPattern of the underlying AutomationElement.
        /// </summary>
        /// <returns>
        /// The SelectionPattern.
        /// </returns>
        private SelectionPattern GetSelectionPattern()
        {
            return this.GetPattern<SelectionPattern>();
        }
    }
}